#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <cassert>
#include <fstream>
#include "../comm/util.hpp"
#include <unordered_map>
#include "../comm/Log.hpp"
#include <algorithm>


namespace modelNs {
    const std::string questions_path = "./questions/";
    using namespace logNs;
    using namespace utilNs;
    // 描述一个题目的具体信息的结构体(类)
    class Question {
        public :
        std::string _number; // 题目的编号
        std::string _title; // 题目的标题
        std::string _star; // 题目的难度
        std::string _desc; // 题目的具体描述
        std::string _header; // 题目的预设代码
        std::string _tail; // 题目的测试用例代码

        int _cpu_limit; // 题目的时间限制
        int _mem_limit; // 题目的空间限制
    };
    class Model {
    public :
        Model() {
            // 首先架在所有题目到题目集合中
            assert(LoadAllQuestions());
        }

        bool LoadAllQuestions() {
            // 读取配置文件
            std::ifstream in(questions_path + "questions.list");
            if (!in.is_open()) {
                LOG(Fatal) << "打开题目列表配置文件失败, 请检查配置文件是否存在" << std::endl;
                return false;
            }
            std::string line;
            while (std::getline(in, line)) {
                // 切割line，分解出题目信息
                std::vector<std::string> tokens;
                StringUtil::splitString(line, &tokens, " ");
                if (tokens.size() != 5) {
                    LOG(Debug) << "解析题目列表配置文件出错, 请检查文件格式" << std::endl;
                    continue;
                }
                Question q;
                q._number = tokens[0];
                q._title = tokens[1];
                q._star = tokens[2];
                q._cpu_limit = std::stoi(tokens[3]);
                q._mem_limit = std::stoi(tokens[4]);

                // 形成对应题目的路径
                std::string question_path = questions_path + q._number + "/";
                FileUtil::ReadeFile(question_path + "desc.txt", &(q._desc));
                FileUtil::ReadeFile(question_path + "header.cpp", &(q._header));
                FileUtil::ReadeFile(question_path + "tail.cpp", &(q._tail));
                _allquestions[std::stoi(q._number)] = q;
            }
            in.close();
            return true;
        }
        // 获取所有题目(对外提供的接口)
        bool GetAllQuestions(std::vector<Question>* all) {
            if (_allquestions.empty()) {
                LOG(Waring) << "题目列表为空, 请尽快检查" << std::endl;
                return false;
            }
            for (auto & q : _allquestions) {
                (*all).push_back(q.second);
            }
            // 对所有题目进行排序
            std::sort((*all).begin(), (*all).end(), [](const Question& q1, const Question& q2) {
                return std::stoi(q1._number) < std::stoi(q2._number);
            });
            return true;
        }

        // 获取指定题目(对外提供的接口)
        bool GetOneQuestion(const int number, Question* q) {
            if (_allquestions.empty()) {
                LOG(Waring) << "题目列表为空, 请尽快检查" << std::endl;
                return false;
            } 
            if (!_allquestions.count(number)) {
                LOG(Waring) << "题目: " << number << "不存在, 请尽快检查题库" << std::endl;
                return false;
            }           
            *q = _allquestions[number];
            return true;
        }
    private :
        std::unordered_map<int, Question> _allquestions; // 所有题目的集合        
    };
};